//this file is part of ePopup
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "stdafx.h"
#include <sys/stat.h>
#include <share.h>
#include <io.h>
#include <atlrx.h>
#include <algorithm>
#include "popup.h"
#include "OtherFunctions.h"
#include "PopupLibUtilities.h"
#include <string>
#include <sstream>


using namespace std;

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

bool isImage(const CString & filePath)
{
	string _file = MFCStringToSTLString(filePath);
	string _ext  = "";
	if (getFileExtension(_file, _ext))
	{
		return (_ext.compare("gif") == 0 || 
				_ext.compare("jpg") == 0);
	}
	return false;
}

bool isVideo(const CString & filePath)
{
	string _file = MFCStringToSTLString(filePath);
	string _ext  = "";
	if (getFileExtension(_file, _ext))
	{
		return (_ext.compare("avi") == 0 || 
				_ext.compare("mpg") == 0 || 
				_ext.compare("wmv") == 0);
	}
	return false;
}

bool isSound(const CString & filePath)
{
	string _file = MFCStringToSTLString(filePath);
	string _ext  = "";
	if (getFileExtension(_file, _ext))
	{
		return (_ext.compare("wav") == 0);
	}
	return false;
}

bool isJpegImage(const char *p_image)
{
	unsigned short _jpgHeaderLittle = 0xFFD8;
	unsigned short _jpgHeaderBig    = 0xD8FF;
	unsigned short _header    = 0x0000;
	memcpy(&_header, p_image, 2);
	return (_header == _jpgHeaderLittle || 
		    _header == _jpgHeaderBig);
}

bool isGifImage(const char *p_image)
{
	unsigned short _gifHeaderLittle = 0x4749;
	unsigned short _gifHeaderBig = 0x4947;
	unsigned short _header    = 0x0000;
	memcpy(&_header, p_image, 2);
	return (_header == _gifHeaderLittle ||
		    _header == _gifHeaderBig);
}

bool isWavSound(const char *p_buffer)
{
	char _format[9] = {'\0'};
	strncpy(&_format[0], &(p_buffer[8]), 8);
	return (strcmp(_format, "WAVEfmt ") == 0);
}

bool isWmvVideo(const char *p_video)
{
	unsigned short _headerLittle = 0x3026;
	unsigned short _headerBig    = 0x2630;
	unsigned short _header       = 0x0000;
	memcpy(&_header, p_video, 2);
	return (_header == _headerLittle ||
		    _header == _headerBig);
}

bool isAviVideo(const char *p_video)
{
	unsigned short _headerLittle = 0x3026;
	unsigned short _headerBig    = 0x2630;
	unsigned short _header       = 0x0000;
	memcpy(&_header, p_video, 2);
	return (_header == _headerLittle ||
		    _header == _headerBig);
}

bool isMpegVideo(const char *p_video)
{
	unsigned short _headerLittle = 0x3026;
	unsigned short _headerBig    = 0x2630;
	unsigned short _header       = 0x0000;
	memcpy(&_header, p_video, 2);
	return (_header == _headerLittle ||
		    _header == _headerBig);
}

stringstream &operator<<(stringstream &logger, LPCTSTR message)
{
	CT2CA str(message);
	logger << string(str);
	return logger;
}

string MFCStringToSTLString(const CString & str)
{
	stringstream s;
	s << (LPCTSTR) str;
	return s.str();
}

bool deleteDirectory(CString rep, bool suppressionDefinitive)
{
    SHFILEOPSTRUCT sh;
    sh.hwnd = NULL;
    sh.wFunc = FO_DELETE;
    sh.pFrom = rep;
    sh.pTo = NULL;
    sh.fFlags = FOF_NOCONFIRMATION|FOF_SILENT;
    if(!suppressionDefinitive)
        sh.fFlags |= FOF_ALLOWUNDO;
    sh.fAnyOperationsAborted = FALSE;
    sh.lpszProgressTitle = NULL;
    sh.hNameMappings = NULL;
    
    return (SHFileOperation(&sh)==0);
}

CString basename(const CString & str)
{
	int lastSlashIndex = str.ReverseFind('\\');
	if (lastSlashIndex == -1) {
		lastSlashIndex = 0;
	} else {
		lastSlashIndex++;
	}
	return str.Right(str.GetLength() - lastSlashIndex);
}

bool absolutePath(const CString & str, CString & ref)
{
	CFileFind f;
	bool _ok = (f.FindFile(str) == TRUE);

	if (_ok)
	{
		f.FindNextFile();
		ref = f.GetFilePath();
	}
	
	return _ok;
}

bool absolutePath(const string & str, string & ref)
{
	CString in, out;
	in = str.c_str();
	
	if (absolutePath(in, out))
	{
		ref = MFCStringToSTLString(out);
		return true;
	}
	else 
	{
		return false;
	}
}

unsigned int splitString(const string & p_str, unsigned int p_maxlinelen, string & _res)
{
	size_t _nbRows = 0;
	size_t _newlineOffset = 0;
	string _str = p_str;
	stringstream _splitted;

	while (_newlineOffset < p_str.length())
	{
		_str = p_str.substr(_newlineOffset, p_maxlinelen);
		size_t _cropAt  = 0;

		// Search for <CR> in the string
		size_t _nextcr  = _str.find_first_of('\n');

		// If one found, let's use it!
		if (_nextcr  != string::npos) {
			_cropAt = _nextcr;
		}
		else if (_str.length() == p_maxlinelen)
		{
			size_t _nextdot = _str.find_last_of('.');
			size_t _nextsp  = _str.find_last_of(' ');
			if (_nextdot != string::npos) _cropAt = max(_cropAt, _nextdot);
			if (_nextsp  != string::npos) _cropAt = max(_cropAt, _nextsp);
		}
		
		if (_cropAt == 0) _cropAt = string::npos;
		
		string s = _str.substr(0, _cropAt);
		_splitted << s;

		_newlineOffset = (_cropAt == string::npos? _newlineOffset + p_maxlinelen: _newlineOffset + _cropAt + 1);

		// Add a <CR> is there is still data to treat
		if (_newlineOffset < p_str.length()) {
			_splitted << endl;
		}

		_nbRows++;
	}
	_res = _splitted.str();
	return _nbRows;
}

CString comboToCString(CComboBox & combo, bool useCursor)
{
	CString str("");
	if (useCursor)
	{
		int selectedTypeIndex = combo.GetCurSel();
		combo.GetLBText(selectedTypeIndex, str);
	}
	else
	{
		combo.GetWindowTextW(str);
	}
	return str;
}

bool CreatePointFontIndirect(CFont &rFont, const LOGFONT *lpLogFont)
{
	LOGFONT logFont = *lpLogFont;
	logFont.lfHeight = FontPointSizeToLogUnits(logFont.lfHeight);
	return rFont.CreateFontIndirect(&logFont) != FALSE;
}

bool CreatePointFont(CFont &rFont, int nPointSize, LPCTSTR lpszFaceName)
{
	LOGFONT logFont = {0};
	logFont.lfCharSet = DEFAULT_CHARSET;
	logFont.lfHeight = nPointSize;
	lstrcpyn(logFont.lfFaceName, lpszFaceName, _countof(logFont.lfFaceName));
	return CreatePointFontIndirect(rFont, &logFont);
}

int FontPointSizeToLogUnits(int nPointSize)
{
	HDC hDC = ::GetDC(HWND_DESKTOP);
	if (hDC)
	{
		POINT pt;
#if 0
		// This is the same math which is performed by "CFont::CreatePointFont",
		// which is flawed because it does not perform any rounding. But without
		// performing the correct rounding one can not get the correct LOGFONT-height
		// for an 8pt font!
		//
		// PointSize	Result
		// -------------------
		// 8*10			10.666 -> 10 (cut down and thus wrong result)
		pt.y = GetDeviceCaps(hDC, LOGPIXELSY) * nPointSize;
		pt.y /= 720;
#else
		// This math accounts for proper rounding and thus we will get the correct results.
		//
		// PointSize	Result
		// -------------------
		// 8*10			10.666 -> 11 (rounded up and thus correct result)
		pt.y = MulDiv(GetDeviceCaps(hDC, LOGPIXELSY), nPointSize, 720);
#endif
		pt.x = 0;
		DPtoLP(hDC, &pt, 1);
		POINT ptOrg = { 0, 0 };
		DPtoLP(hDC, &ptOrg, 1);
		nPointSize = -abs(pt.y - ptOrg.y);
		ReleaseDC(HWND_DESKTOP, hDC);
	}
	return nPointSize;
}
// Wrapper for _tmakepath which ensures that the outputbuffer does not exceed MAX_PATH
// using a smaller buffer  without checking the sizes prior calling this function is not safe
// If the resulting path would be bigger than MAX_PATH-1, it will be empty and return false (similar to PathCombine)
bool _tmakepathlimit(TCHAR *path, const TCHAR *drive, const TCHAR *dir, const TCHAR *fname, const TCHAR *ext){
	if (path == NULL){
		ASSERT( false );
		return false;
	}

	uint32 nSize = 64; // the function should actually only add 4 (+1 nullbyte) bytes max extra
	if (drive != NULL)
		nSize += _tcsclen(drive);
	if (dir != NULL)
		nSize += _tcsclen(dir);
	if (fname != NULL)
		nSize += _tcsclen(fname);
	if (ext != NULL)
		nSize += _tcsclen(ext);

	TCHAR* tchBuffer = new TCHAR[nSize];
	_tmakepath(tchBuffer, drive, dir, fname, ext);

	if (_tcslen(tchBuffer) >= MAX_PATH){
		path[0] = _T('\0');
		ASSERT( false );
		delete[] tchBuffer;
		return false;
	}
	else{
		_tcscpy(path, tchBuffer);
		delete[] tchBuffer;
		return true;
	}
}
